﻿
using FreeSql;

using GCC.APIContainer;
using GCC.Container.Abstracts;
using GCC.Container.Common;
using GCC.Container.JobManager;
using GCC.Container.LogProviders;

using Microsoft.Extensions.Caching.Redis;
using Microsoft.Extensions.Options;

using APMClient = System.APMServer.Client.Manager;
using CacheManager = GCC.Container.Cache.Manager;
using PluginManager = GCC.Container.PluginLoader.Manager;

namespace GCC.JobContainer
{
    public class Program
    {
        /// <summary>
        /// 本地缓存实例
        /// </summary>
        private static readonly CacheManager _localCache = new();
        /// <summary>
        /// 日志服务
        /// </summary>
        private static AbsGCCLogger? _logger;
        /// <summary>
        /// 认证中心地址
        /// </summary>
        private static string _authCenterUrl = "";
        /// <summary>
        /// 认证前端的Header key
        /// </summary>
        private static string _authHeaderKey = "";
        /// <summary>
        /// 配置服务中心地址
        /// </summary>
        private static string _configCenter = "";
        /// <summary>
        /// APM客户端
        /// </summary>
        private static APMClient? _apmClient = null;
        /// <summary>
        /// 当前点名称
        /// </summary>
        private static string _pointName = "";
        /// <summary>
        /// 当前启动事件ID
        /// </summary>
        private static readonly string _eventID = Guid.NewGuid().ToString("N");
        /// <summary>
        /// 远程库类型
        /// </summary>
        private static int _globalDBType = 0;
        /// <summary>
        /// 本地DB类型
        /// </summary>
        private static int _localDBType = 0;
        /// <summary>
        /// 远程库地址
        /// </summary>
        private static string _globalDBAddress = "";
        /// <summary>
        /// 远程读库地址
        /// </summary>
        private static string _globalReadDBAddress = "";
        /// <summary>
        /// 本地库地址
        /// </summary>
        private static string _localDBAddress = "";
        /// <summary>
        /// 本地读库地址
        /// </summary>
        private static string _localReadDBAddress = "";
        /// <summary>
        /// IM服务器地址
        /// </summary>
        private static string _imServerAddress = "";
        public static void Main()
        {

            var checkRes = SystemChecker.Check(
             out _globalDBType
             , out _localDBType
             , out _globalDBAddress
             , out _globalReadDBAddress
             , out _localDBAddress
             , out _localReadDBAddress
             , out _pointName
             , out _authCenterUrl
             , out _configCenter
             );

            if (!checkRes)
            {
                Console.BackgroundColor = ConsoleColor.Red;
                Console.WriteLine("System environment variable failed, system shutdown.");
                return;
            }
            else
            {
                Console.WriteLine("System environment variable completed");
            }
            if (string.IsNullOrWhiteSpace(_pointName) || string.IsNullOrWhiteSpace(_authCenterUrl))
            {
                return;
            }
            _logger = GCCLoggerProvider.GetInstance(ContainerConfigManager.Instance.Config.SystemLog ?? new LogOptions()).CreateLogger<Program>();

            if (GCCLoggerProvider.Instance is null)
            {
                Console.WriteLine($"System log init failed, system shutdown.");
                return;
            }

            _authHeaderKey = ContainerConfigManager.Instance.Config.AuthHeader;

            GCCContext._authHeadKey = _authHeaderKey;

            DBManager.Instance.Init(_globalDBType, _localDBType, _globalDBAddress, _globalReadDBAddress, _localDBAddress, _localReadDBAddress);
            Console.WriteLine("DB Instance create completed.");

            Console.BackgroundColor = ConsoleColor.Green;
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine($"Currently, the auth head key is {_authHeaderKey}");
            Console.WriteLine($"Currently, the auth center is {_authCenterUrl}");
            Console.WriteLine($"Currently, the config center is {_configCenter}");
            Console.WriteLine($"Currently, the point name is {_pointName}");
            Console.WriteLine($"Currently, the location db is {(Enum.GetName((DataType)_localDBType))} host:{_localDBAddress}");
            Console.WriteLine($"Currently, the location  read db host:{_localReadDBAddress}");
            Console.WriteLine($"Currently, the global db is {(Enum.GetName((DataType)_globalDBType))} host:{_globalDBAddress}");
            Console.WriteLine($"Currently, the global  read db host:{_globalReadDBAddress}");
            Console.ResetColor();
            Console.WriteLine("\r\n\r\n");



            PluginManager.Instance.DBInitiated(DBManager.Instance);
            _logger.Information("Plugin's db instance set completed.");
            System.ConfigCenter.Client.ClientInstance.Init(_configCenter);
            _logger.Information("ConfigCenter client init completed.");
            System.AuthCenter.Client.Manager.Init(_authCenterUrl);
            _logger.Information("AuthCenter client init completed.");


            try
            {
                InitServerByConfigCenterConfig();
            }
            catch (Exception ex)
            {
                _logger.Error($"Init Server By Config Center Config failed, maybe configserver's config was error, system shutdown!", exception: ex);
                return;
            }


            PluginManager.Instance.SystemStarted(new GCCContext(_localCache, _pointName, _apmClient));



            _logger?.Information("System Try init job services.");
            InitJobServer();
            _logger?.Information("System started event called, ready to run!");


            while (true)
            {
                var res = Console.ReadLine();
                if (res is not null)
                {
                    break;
                }
            }


        }
        /// <summary>
        /// 通过配置服务器初始化配置
        /// </summary>
        private static void InitServerByConfigCenterConfig()
        {
            var redisServer = System.ConfigCenter.Client.Manager.GetByPath(new string[] { _pointName, "LocalRedisServer" }, _eventID);
            if (!string.IsNullOrWhiteSpace(redisServer))
            {
                var options = Options.Create(new RedisCacheOptions()
                {
                    Configuration = redisServer,
                    InstanceName = "Local RedisCache",
                });
                var cacheInstance = new RedisCache(options);
                try
                {
                    cacheInstance.Refresh("test");
                    _localCache.PushNewClient(new Container.Cache.CacheInstance(cacheInstance)
                    {
                        Available = true,
                        Name = "Local RedisCache",
                        Priority = 1
                    });
                }
                catch (Exception ex)
                {
                    _logger?.Critical($"Redis server error, skip redis client.", exception: ex);
                }
            }
            _localCache.Lock();
            _logger?.Information("Cache instance locked!");

            var apmServerAddress = System.ConfigCenter.Client.Manager.GetByPath(new string[] { _pointName, "APMServer" }, _eventID);
            if (!string.IsNullOrWhiteSpace(apmServerAddress))
            {
                _apmClient = new APMClient(apmServerAddress);
            }

            _imServerAddress = System.ConfigCenter.Client.Manager.GetByPath(new string[] { _pointName, "IMServer" }, _eventID);
            if (string.IsNullOrWhiteSpace(_imServerAddress))
            {
                _logger?.Critical($"IM server's config was empty im server can not to use");
            }
            try
            {
                var list = System.Text.Json.JsonSerializer.Deserialize<string[]>(_imServerAddress);
                if (list is not null)
                {
                    System.IMServer.Client.Manager.InitIMServers(list);
                }
            }
            catch
            {
                _logger?.Critical($"IM server's config string was invalid, please chech it currently config info:{_imServerAddress}. IM operations cann't to use.");
            }
        }
        /// <summary>
        /// 初始化服务内容
        /// </summary>
        private static void InitJobServer()
        {
            PluginManager.Instance.AllPluginInstance.Where(plugin => plugin.AllJobs.Count != 0)
                .ToList().ForEach(plugin =>
                {
                    foreach (var item in plugin.AllJobs)
                    {
                        JobManager.Instance.PushNewJobInfo(item);
                    }
                });

            JobManager.Instance.CreateContextAction = () => new GCCContext(_localCache, _pointName, _apmClient);
            JobManager.Instance.StartService();
        }
    }
}